package replay

import (
	"encoding/binary"
	"fmt"
	"io"
	"os"
	"path/filepath"
	"sync"
	"time"
)

// TimeRotatingRecorder 支持时间占位符替换的记录器
type TimeRotatingRecorder struct {
	saveFormat     string     // 原始保存格式字符串
	baseDir        string     // 基本路径不解析
	currentFile    *os.File   // 当前打开的文件
	currentPath    string     // 当前文件路径
	mu             sync.Mutex // 线程安全锁
	protocolPrefix []byte     // 协议前缀
	OnNewFile      func(filename string, w io.Writer)
	OnCloseFile    func(filename string, w io.Writer)
}

func NewTimeRotatingRecorder() *TimeRotatingRecorder {
	r := &TimeRotatingRecorder{}
	return r
}

// SetProtocolPrefix 设置协议前缀
func (r *TimeRotatingRecorder) SetProtocolPrefix(prefix []byte) {
	r.protocolPrefix = make([]byte, len(prefix))
	copy(r.protocolPrefix, prefix)
}

func (r *TimeRotatingRecorder) SetSaveFormat(s string) {
	r.mu.Lock()
	defer r.mu.Unlock()
	r.saveFormat = s
}

func (r *TimeRotatingRecorder) SetBaseDir(s string) {
	r.mu.Lock()
	defer r.mu.Unlock()
	r.baseDir = s
}

func (r *TimeRotatingRecorder) Write(data []byte) (n int, err error) {
	err = r.WriteWithNowTime(time.Now(), data)
	n = len(data)
	return
}

// Write 写入带外部时间戳的数据，自动按时间切换文件
func (r *TimeRotatingRecorder) WriteWithNowTime(nowTime time.Time, data []byte) error {
	r.mu.Lock()
	defer r.mu.Unlock()

	// 生成当前时间对应的文件路径
	targetPath, err := r.generateFilePath(nowTime)
	if err != nil {
		return fmt.Errorf("生成目标文件路径失败: %v", err)
	}

	// 检查是否需要切换文件
	if targetPath != r.currentPath {
		if err := r.closeCurrentFile(); err != nil {
			return fmt.Errorf("close current file fail, %v", err)
		}
		if err := r.openFile(targetPath); err != nil {
			return fmt.Errorf("open new file fail, %v", err)
		}
	}

	// 如果设置了协议前缀，先写入前缀
	if len(r.protocolPrefix) > 0 {
		if _, err := r.currentFile.Write(r.protocolPrefix); err != nil {
			return err
		}
	}

	// 写入数据（时间戳+长度+数据）
	if err := binary.Write(r.currentFile, binary.LittleEndian, nowTime.UnixNano()); err != nil {
		return err
	}
	if err := binary.Write(r.currentFile, binary.LittleEndian, uint32(len(data))); err != nil {
		return err
	}
	if _, err := r.currentFile.Write(data); err != nil {
		return err
	}

	return nil
}

// GetCurrentFile 返回当前正在写入的文件完整路径
func (r *TimeRotatingRecorder) GetCurrentFile() string {
	r.mu.Lock()
	defer r.mu.Unlock()
	return r.currentPath
}

// GetSaveFormat 返回创建时使用的原始保存格式
func (r *TimeRotatingRecorder) GetSaveFormat() string {
	return r.saveFormat
}

// Close 关闭记录器
func (r *TimeRotatingRecorder) Close() error {
	r.mu.Lock()
	defer r.mu.Unlock()
	return r.closeCurrentFile()
}

// 生成带时间戳的文件路径
func (r *TimeRotatingRecorder) generateFilePath(t time.Time) (string, error) {
	path := ParseTimeFormat(r.saveFormat, t)

	if len(r.baseDir) > 0 {
		path = filepath.Join(r.baseDir, path)
	}

	// 创建所需的目录
	dir := filepath.Dir(path)
	if err := os.MkdirAll(dir, 0755); err != nil {
		return "", fmt.Errorf("make dir fail, %v", err)
	}

	return path, nil
}

// 打开文件并更新当前状态
func (r *TimeRotatingRecorder) openFile(path string) error {
	f, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
	if err != nil {
		return err
	}

	r.currentFile = f
	r.currentPath = path
	evt := r.OnNewFile
	if evt != nil {
		evt(path, r.currentFile)
	}
	return nil
}

// 关闭当前文件
func (r *TimeRotatingRecorder) closeCurrentFile() error {
	if r.currentFile != nil {
		evt := r.OnCloseFile
		if evt != nil {
			evt(r.currentPath, r.currentFile)
		}

		err := r.currentFile.Close()
		r.currentFile = nil
		r.currentPath = ""
		return err
	}
	return nil
}
